home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / language / embedded / mcu11 / examples.arc / EX10 < prev    next >
Text File  |  1988-11-29  |  27KB  |  846 lines

  1. *****
  2. *
  3. *  This file contains all Examples for section 10 of the User's Manual
  4. *
  5. *****
  6.  
  7. ** Equates - Registers will be addressed with Ind,X mode
  8. *
  9. REGBAS    EQU    $1000    Starting address for register block
  10. PORTB    EQU    $04    Output port B
  11. OC1M    EQU    $0C    OC1M7,OC1M6,OC1M5,OC1M4;OC1M3,-,-,-
  12. OC1D    EQU    $0D    OC1D7,OC1D6,OC1D5,OC1D4;OC1D3,-,-,-
  13. TCNT    EQU    $0E    Free running counter (16-bit)
  14. TIC1    EQU    $10    IC1 register (16-bit)
  15. TOC1    EQU    $16    OC1 register (16-bit)
  16. TOC2    EQU    $18    OC2 register (16-bit)
  17. TOC3    EQU    $1A    OC3 register (16-bit)
  18. TCTL1    EQU    $20    OM2,OL2,OM3,OL3;OM4,OL4,OM5,OL5
  19. TCTL2    EQU    $21    -,-,EDG1B,EDG1A;EDG2B,EDG2A,EDG3B,EDG3A
  20. TMSK1    EQU    $22    OC1I,OC2I,OC3I,OC4I;OC5I,IC1I,IC2I,IC3I
  21. TFLG1    EQU    $23    OC1F,OC2F,OC3F,OC4F;OC5F,IC1F,IC2F,IC3F
  22. TMSK2    EQU    $24    TOI,RTII,PAOVI,PAII;-,-,PR1,PR0
  23. TFLG2    EQU    $25    TOF,RTIF,PAOVF,PAIF;-,-,-,-
  24.  
  25. *** EVB Routine Addresses & Pseudo Vector Equates
  26.  
  27. .OUTA    EQU    $FFB8    Print character in A-reg
  28. .OUTCRL    EQU    $FFC4    Output <cr><lf>
  29. .OUTSTO    EQU    $FFCA    Output Msg seg (no <cr,lf>)
  30. .OUTSTR    EQU    $FFC7    Output Msg w/ leading <cr,lf>
  31.  
  32. PVIC1    EQU    $00E8    EVB Pseudo Vector for IC1
  33. PVTOF    EQU    $00D0    EVB Pseudo Vector for TOF
  34. PVOC2    EQU    $00DC    EVB Pseudo Vector for OC2
  35. PVOC1    EQU    $00DF    EVB Pseudo Vector for OC1
  36.  
  37. *** RAM Variable Assignments
  38.  
  39.     ORG    $D000    Start variables in EVB RAM (upper half)
  40.     
  41. HDLY    RMB    2    Half-cycle delay (in 0.5╡S increments)
  42. PWMP1P    RMB    1    1% of PWM period (1 to 256 cycles) Ex 10-7
  43. PWMDC1    RMB    1    Duty cycle for PWM signal at OC2 pin
  44. PWMDC2    RMB    1    Duty cycle for PWM signal at OC3 pin
  45. IC1DUN    RMB    1    flag: 0-not done,1-pulse measured
  46. IC1MOD    RMB    1    s/w mode flag: FF-off,0-1st,1-last edge
  47. OVCNT1    RMB    1    Overflow count (upper 8-bits of result)
  48. RES1    RMB    2    Pulse Width in cycles (16-bits)
  49. HTEMP    RMB    3    Temp for H6TOD8 (3 bytes)
  50. FRSTE    RMB    2    Time of first edge (16-bits)
  51. PERC    RMB    2    Period in cycles (16-bits)
  52. TEMP1    RMB    2    Temp for conversion (16-bits)
  53. FREQH    RMB    2    Freq in Hex (16-bits)
  54. HPW    RMB    2    Pulse Width (16-bits hex)
  55. DBUFR    RMB    8    Decimal result buffer (8 bytes ASCII)
  56. * Some routines use only first 5 bytes of DBUFR
  57. PWMPER    RMB    2    Period of PWM signals in (cycles)
  58. OFFHI    RMB    2    OC2 high offset (calculated)
  59. OFFLO    RMB    2    OC2 low offset (calculated)
  60.  
  61.     ORG    $C000    Prog starts in EVB RAM at $C000
  62.  
  63. ***
  64. *  TIMER EXAMPLE 10-1a  Measuring Period with Input Capture
  65. *
  66. * Uses polling rather than interrupts.
  67. * Measures period between two rising edges at IC1 pin.
  68. * Overflows not considered so max period is 65,535 cyc
  69. * Min period measurable with this program is about 27 cyc
  70. *
  71. * This program runs on an EVB board and displays results
  72. * on the EVB terminal display.
  73. ***
  74.  
  75. PERTOP    LDS    #$0047    Top of User's stack area on EVB
  76.     LDX    #REGBAS    Point to register block
  77.     LDAA    #%00010000
  78.     STAA    TCTL2,X    EDG1B:EDG1A = 0:1, rising edges
  79.     LDAA    #$04
  80.     STAA    TFLG1,X    Clear any old OC1 flag
  81.  
  82. * Ready to detect first rising edge
  83.     BRCLR    TFLG1,X    $04 *    Loop here until edge
  84.  
  85. * First edge detected
  86.     LDD    TIC1,X    Read time of first edge
  87.     STD    FRSTE    Save first capture value
  88.     LDAA    #$04
  89.     STAA    TFLG1,X    Clear IC1F before next edge
  90.  
  91. * Ready to capture time of second edge
  92.     BRCLR    TFLG1,X    $04 *    Loop here until edge
  93.  
  94. * Second edge detected
  95.     LDD    TIC1,X    Read time of second edge
  96.     SUBD    FRSTE    2nd - 1st -> D
  97.     STD    PERC    Save result (period in cycles)
  98.  
  99. * The period of the signal at the PA2/IC1 pin has been measured
  100. * and the time is stored at "PERC" as a 16-bit hex number
  101. * representing the number of CPU bus cycles that elapsed
  102. * between two rising edges.
  103.  
  104. ***
  105. *  TIMER EXAMPLE 10-1b  Changing Period to Frequency
  106. *
  107. * The period found in example 10-1a is expressed as a number
  108. * of bus cycles (@E=2MHz, 1 bus cycle=0.5╡S) and it is
  109. * currently in the D-reg and at "PERC".  Values < or = $20
  110. * will be considered too small (freq too high) to be
  111. * accurately measured with this program and will be trapped
  112. * out to make the period to frequency conversion program easier.
  113. * $0021 corresponds to 60,606 Hz, $FFFF is 30.5 Hz.
  114. ***
  115.  
  116.     LDX    PERC    Period in cycles (16-bits)
  117.     CPD    #32    ($20) Check against min allowed
  118.     BHI    OKP    Skip if OK
  119.     JMP    OUTRNG    Else go say it was too small
  120. OKP    LDD    #32    X=period; D=32
  121.     FDIV        D/X -> X; r -> D
  122.     STX    TEMP1    (Freq*16)╓1,000,000; radix left of MSB
  123. *
  124. * We now have frequency but it isn't in a good displayable
  125. * form yet.  If we move the binary radix 16 places to the right
  126. * we would have a 16-bit integer representing
  127. * [(2**20)/(10**6) x freq] or [((1,048,576)/(1,000,000))*freq].
  128. * By adding and subtracting binary multiples of the freq we
  129. * will arrive at [((1,000,000)/(1,000,000))*freq]
  130. *
  131. *  1,048,576  16-bit starting value ((2**20)freq)╓(10**6)
  132. * -   32,768  2**15
  133. * -   16,384  2**14
  134. * +      512  2**9
  135. * +       64  2**6
  136. * =1,000,000 * freq
  137. *
  138. * The limitation of 33 ($21) cycles min was selected so
  139. * (1,048,576/1,000,000)*freq would fit in 16-bits so we would
  140. * only need 1 FDIV.  Although it is pretty easy to extend the
  141. * precision of an FDIV.
  142. *
  143. * The partial results which are added and subtracted in this
  144. * program may have an error of ▒1 LSB ea. because I trunkated
  145. * rather than rounding.
  146. *
  147.     LDD    TEMP1    (2**20)f; where f=freq╓(10**6)
  148.     LSRD
  149.     LSRD
  150.     LSRD        A=(2**9)f; D=(2**17)f
  151.     CLR    FREQH    Clear upper half of hex freq location
  152.     STAA    FREQH+1    FREQH is a temp = 512f
  153.     LSRD
  154.     LSRD        now D=(2**15)f or 32,768f
  155.     STD    TEMP1    Needs to be in mem for 16-bit subtract
  156.     XGDX        D=(2**20)f; X=(2**15)f
  157.     SUBD    TEMP1    First subtraction (-32K)
  158.     XGDX        Working result -> X; D=(2**15)f
  159.     LSRD        A=(2**6)f; D=(2**14)f
  160.     STD    TEMP1    Put in mem so you can subtract
  161.     ADDA    FREQH+1    (512+64)f
  162.     STAA    FREQH+1    Update low half of FREQH
  163.     XGDX        D=1,015,808*f; X=junk
  164.     SUBD    TEMP1    999,424*f
  165.     ADDD    FREQH    1,000,000*f = frequency
  166.     STD    FREQH    Save the 16-bit binary result
  167. *
  168. * Since most of us don't think in hexidecimal, let's change to
  169. * decimal before printing.  The subroutine (HTODP) is shown at
  170. * the end of this listing.
  171. *
  172. * The display will look like...
  173. *
  174. *ppppp Cyc     fffff Hz      ---or like---
  175. *Freq. is too high
  176. *
  177. * where ppppp is period in cycles & fffff is freq. (decimal)
  178. *
  179. * EVB subroutines will be used and when done we will jump
  180. * back to the beginning and repeat continuously.
  181. *
  182.     JSR    .OUTCRL    Print a <cr,lf>
  183.     LDX    #PERC    Point at hex period
  184.     JSR    HTOD    Convert to 5 digit decimal
  185.     JSR    P5DEC    Print 5 digi decimal (not leading 0s)
  186.     LDX    #MSGCYC    Point at " Cycles     "
  187.     JSR    .OUTSTO    Print message segment
  188.     LDX    #FREQH    Point at hex frequency
  189.     JSR    HTOD    Convert to 5 digit decimal
  190.     JSR    P5DEC    Print 5 digi decimal (not leading 0s)
  191.     LDX    #MSGHZ    Point at " Hz"
  192.     JSR    .OUTSTO    Print message segment
  193. JTOP    JMP    PERTOP    Go back to top & measure another period
  194.  
  195. OUTRNG    LDX     #MSGER1    Point at "Freq. is too high"
  196.     JSR    .OUTSTR    Print message w/ leading <cr,lf>
  197.     BRA    JTOP    Go back to top & measure another period
  198. *
  199. ***** END Ex 10-1b
  200.  
  201. ***
  202. *  TIMER EXAMPLE 10-2  Measuring Pulses With Input Capture
  203. *
  204. * Uses interrupts.
  205. * Measures time between a rising edge and a falling edge
  206. * (period of a positive pulse) at the IC1 pin.
  207. * Overflows not considered so max is 65,536 cyc
  208. * Min time measurable with this program is about __ cyc
  209. *
  210. * This program runs on an EVB board and displays results
  211. * on the EVB terminal display.
  212. ***
  213.  
  214. * Initialization Portion
  215. *
  216. PWINZ    LDS    #$0047    Top of User's stack area on EVB
  217.     LDAA    #$7E    Jump (extended) Opcode
  218.     STAA    PVIC1    IC1 Pseudo Vector
  219.     LDX    #SV2IC1    Address of IC1 service routine
  220.     STX    PVIC1+1    Finish jump instruc to IC1 routine
  221.  
  222. * Main Program Portion of Pulse Width program
  223. *
  224. PWTOP    LDX    #REGBAS    Point to register block
  225.     LDAA    #%00010000    Top of Main for PW24 prog
  226.     STAA    TCTL2,X    EDG1B:EDG1A = 0:1, IC1 rising edges
  227.     LDAA    #$FF
  228.     STAA    IC1MOD    FF-IC1 off; 0-1st edge; 1-last edge
  229.     CLR    IC1DUN    Signal pulse not done
  230.     BCLR    TFLG1,X $FB    clear IC1F (if any)
  231.     BSET    TMSK1,X $04    enable IC1 interrupts
  232.     CLI        Enable Interrupts
  233.  
  234. WAITL2    LDAA    IC1DUN    Sets after pulse done
  235.     BEQ    WAITL2    Tight loop till pulse has been timed
  236.     SEI        Pulse done, disable interrupts
  237.  
  238. * Display pulse width as xx,xxx microseconds (32,768 max)
  239.     JSR    .OUTCRL    Begin printing result
  240.     LDD    HPW    number of cyc (0.5╡S/cyc)
  241.     LSRD        16-bit ╓2 to change to ╡S
  242.     BCC    ARNUP2    ? need to round result ?
  243.     ADDD    #1    yes; round up
  244. ARNUP2    STD    HPW    Update hex Pulse width
  245.     LDX    #HPW    Point at hex pulse width
  246.     JSR    HTOD    Convert to 5 digit decimal
  247.     JSR    P5DEC    Print 5 digi decimal (not leading 0s)
  248.     LDX    #MSGMS    Point at rest of display line
  249.     JSR    .OUTSTO    Print " millieconds"
  250.     BRA    PWTOP    Goto top of main & repeat
  251. *
  252. * END of Main Program Portion
  253.  
  254. ***
  255. * SV2IC1 - Input Capture 1 service routine
  256. *
  257. * Called first when a rising edge is detected and again when
  258. * a falling edge is detected.
  259. ***
  260. SV2IC1    LDX     #REGBAS    point at top of register block
  261.     INC    IC1MOD    $FF->0 at 1st edge; 0->1 at 2nd
  262.     BNE    NO1ST2    if not 0, this is trailing edge
  263.  
  264. * Process leading edge of pulse
  265.     LDD    TIC1,X    read time of first edge
  266.     STD    FRSTE    save till next capture
  267. * Reconfigure IC1 for trailing falling edge
  268.     BCLR    TCTL2,X $30    EDG1B:EDG1A->0:0
  269.     BSET    TCTL2,X $20    EDG1B:EDG1A->1:0
  270.     BRA    OU2IC1    done processing first edge
  271.  
  272. * Process trailing edge of pulse
  273. NO1ST2    LDD    TIC1,X    get time of trailing edge
  274.     SUBD    FRSTE    time of last minus time of first
  275.     STD    HPW    update result
  276.     BCLR    TCTL2,X $30    disable IC1
  277.     LDAA    #1
  278.     STAA    IC1DUN    signal pulse measured
  279. OU2IC1    BCLR    TFLG1,X $FB    clear IC1F
  280.     RTI        ** Return from IC1 service **
  281. *
  282. ***** END Ex 10-2
  283.  
  284. ***
  285. *
  286. *  TIMER EXAMPLE 10-3  Measuring Long Periods with IC
  287. *
  288. * Uses interrupts.
  289. * Measures period between two rising edges at the IC1 pin.
  290. * Overflows are counted so max is 16,777,215 cyc (~8.38 Sec)
  291. * Min time measurable with this program is about 70 cyc
  292. *
  293. * This program runs on an EVB board and displays results
  294. * on the EVB terminal display.
  295. ***
  296.  
  297. * Initialization Portion
  298. *
  299. P24INZ    LDS    #$0047    Top of User's stack area on EVB
  300.     LDAA    #$7E    Jump (extended) Opcode
  301.     STAA    PVTOF    TOF Pseudo Vector see manual text
  302.     STAA    PVIC1    IC1 Pseudo Vector
  303.     LDX    #SV3TOF    Address of TOF service routine
  304.     STX    PVTOF+1    Finish jump instruc to TOF routine
  305.     LDX    #SV3IC1    Address of IC1 service routine
  306.     STX    PVIC1+1    Finish jump instruc to IC1 routine
  307.  
  308. * Main Program Portion of PER24 program
  309. *
  310. PER24T    LDX    #REGBAS    Point to register block
  311.     LDAA    #%00010000    Top of Main for PER24 prog
  312.     STAA    TCTL2,X    EDG1B:EDG1A = 0:1, IC1 rising edges
  313.     LDAA    #$FF
  314.     STAA    IC1MOD    FF-IC1 off; 0-1st edge; 1-last edge
  315.     CLR    IC1DUN    Signal period not done
  316.     BCLR    TFLG1,X $FB    clear IC1F (if any)
  317.     BCLR    TFLG2,X $7F    clear TOF (if any)
  318.     BSET    TMSK1,X $04    enable IC1 interrupts
  319.     BSET    TMSK2,X $80    enable TOF interrupts
  320.     CLI        Enable Interrupts
  321.  
  322. WAITL3    LDAA    IC1DUN    Sets after pulse done
  323.     BEQ    WAITL3    Tight loop till pulse has been timed
  324.     SEI        Pulse done, disable interrupts
  325.  
  326. * Display period as x.xxxxxx Seconds (to nearest ╡S)
  327.     LDX    #OVCNT1    Point at upper byte of 6 digit hex
  328.     LSR    0,X    24-bit ╓2 to change to ╡S
  329.     ROR    1,X    (1cyc=0.5╡S)
  330.     ROR    2,X    RORs include carry
  331.     BCC    ARNUP3    ? need to round result ?
  332.     INC    2,X    yes; round up
  333.     BNE    ARNUP3    carry to middle byte ?
  334.     INC    1,X    yes
  335.     BNE    ARNUP3    carry to high byte ?
  336.     INC    0,X    yes
  337. ARNUP3    JSR    H6TOD8    Convert to 8 digit decimal
  338.     JSR    .OUTCRL    Begin printing result
  339.     LDX    #DBUFR+1 Start at 2nd digit (1st is 0)
  340.     LDAA    0,X    Seconds digit
  341.     JSR    .OUTA    Print
  342.     LDAA    #'.'    ASCII period
  343.     JSR    .OUTA    Print
  344. DUMPLP    INX        Advance pointer to next digt
  345.     LDAA    0,X    get digit
  346.     JSR    .OUTA    Print it
  347.     CPX    #DBUFR+7    Was that the last ?
  348.     BNE    DUMPLP    If not continue
  349.     LDX    #MSGSEC    Point at rest of display line
  350.     JSR    .OUTSTO    Print " Seconds"
  351.     BRA    PER24T    Goto top of main & repeat
  352. *
  353. * END of Main Program Portion
  354.  
  355. ***
  356. * SV3TOF - Timer Overflow service routine
  357. *
  358. * Called whenever any timer overflow is detected.  If the IC1
  359. * pulse measurement is in progress (IC1MOD positive) then
  360. * the overflow counter (upper 8-bits of period) is incremented.
  361. ***
  362. SV3TOF    TST    IC1MOD    if 0 or 1, IC1 active so count TOFs
  363.     BMI    OU3TOF    if neg, IC1 not active
  364.     INC    OVCNT1    increment IC1 overflow count
  365. OU3TOF    LDAA    #$80
  366.     STAA    REGBAS+TFLG2    Clear overflow flag
  367.     RTI        ** Return from TOF service **
  368.  
  369. ***
  370. * SV3IC1 - Input Capture 1 service routine
  371. *
  372. * Called first when a rising edge is detected and again when
  373. * another rising edge is detected.
  374. ***
  375. SV3IC1    LDX     #REGBAS    point at top of register block
  376.     INC    IC1MOD    $FF->0 at 1st edge; 0->1 at 2nd
  377.     BNE    NO1ST3    if not 0, this is second edge
  378.  
  379. * Process first edge of pulse
  380.     CLR    OVCNT1    Zero the overflow count
  381.     LDD    TIC1,X    Read time of first edge
  382.     STD    RES1    Save till next capture
  383.     BMI    OU3IC1    Done if IC was before any overflow
  384.     LDAA    TFLG2,X    Check for TOF in MSB
  385.     BPL    OU3IC1    If no overflow, you're done
  386.     DEC    OVCNT1    This TOF shouldn't count
  387. * decrement OVCNT1 to -1, TOF svc routine will inc to zero
  388.     BRA    OU3IC1    Done processing first edge
  389.  
  390. * Process second edge of pulse
  391. NO1ST3    LDD    TIC1,X    Get time of second edge
  392.     BMI    ARNOV1    If MSB=1, skip TOF check
  393.     TST    TFLG2,X    Check for overflow
  394.     BPL    ARNOV1    If no TOF, skip increment
  395.     INC    OVCNT1    TOF was before edge so count it
  396. ARNOV1    SUBD    RES1    Time of last minus time of first
  397.     STD    RES1    Update result
  398.     BCC    RES1OK    Check for borrow
  399.     DEC    OVCNT1    If borrow, fix overflow count
  400. RES1OK    BCLR    TCTL2,X $30    Disable IC1
  401.     LDAA    #1
  402.     STAA    IC1DUN    Signal pulse measured
  403. OU3IC1    BCLR    TFLG1,X $FB    Clear IC1F
  404.     RTI        ** Return from IC1 service **
  405. *
  406. ***** END Ex 10-3
  407.  
  408. ***
  409. *
  410. *  TIMER EXAMPLE 10-4  Simple Output Compare Example
  411. *
  412. * Ex10-4 uses polled mode.
  413. * Generate a 10mS period like you would use to time an EE write
  414. * but rather than wearout the EEPROM just change an output pin
  415. *
  416. * Example 10-4 runs on an EVB board and drives PB0 high for
  417. * 10mS once every 30mS so you can see on an oscilloscope.
  418. ***
  419.  
  420. INZA    LDX    #REGBAS    Point to register block
  421.     LDAA    #$80
  422.     STAA    TFLG1,X    Clear any pending OC1F flag
  423.     CLR    PORTB,X    Initialize port B to zeros
  424.  
  425. TOP4A    LDAA    #1    Top of Ex10-4a
  426.     STAA    PORTB,X    Set LSB of port B
  427.  
  428. * This is where the 10mS delay part actually starts
  429. *
  430.     LDD    TCNT,X    Get current timer count
  431.     ADDD    #20000    What will count be in 10mS?
  432.     STD    TOC1,X    Set OC1 to trigger then
  433. LP1    BRCLR    TFLG1,X $80 LP1    Loop here till OC1F=1
  434. *
  435. *Delay is actually done here; rest is just support
  436.  
  437.     BCLR    TFLG1,X $7F    Clear OC1F
  438.     CLR    PORTB,X    Clear PB0 pin
  439.     LDY    #5710    5710*(7~/loop)= about 20mS    
  440. DLP1    DEY        Top of software delay loop
  441.     BNE    DLP1    Loop 'till Y is zero
  442.     BRA    TOP4A    Repeat continuously for O-scope
  443. *
  444. ***** END Ex 10-4
  445.  
  446. ***
  447. *
  448. *  TIMER EXAMPLE 10-5  Square wave using Output Compare
  449. *
  450. * Ex10-5 uses interrupts.
  451. * Generate a square wave at the PA6 output pin using OC2
  452. *
  453. * This program runs on an EVB board.  The half-cycle delay
  454. * time is entered into the double byte variable "HDLY" at
  455. * $D000,D001 with a memory modify before going to the program.
  456. ***
  457.  
  458. TOP5    LDS    #$0047    Top of User's stack area on EVB
  459.     LDAA    #$7E    Jump (extended) Opcode
  460.     STAA    PVOC2    OC2 Pseudo Vector see manual text
  461.     LDX    #SV5OC2    Address of OC2 service routine
  462.     STX    PVOC2+1    Finish jump instruc to TOF routine
  463.     LDX    #REGBAS    Point to register block
  464.     LDAA    #%01000000    OM2:OL2 = 0:1
  465.     STAA    TCTL1,X    Setup OC2 for toggle on each compare
  466.     STAA    TFLG1,X    Clear any pending OC2F
  467.     STAA    TMSK1,X    Enable OC2 interrupts
  468.     CLI        Enable Interrupts
  469.     BRA    *    Interrupt driven; so twiddle thumbs
  470.  
  471. ***
  472. * SV5OC2 - Output Compare 2 service routine
  473. *
  474. * Called at each OC2 interrupt.
  475. ***
  476. SV5OC2    LDD     HDLY    Get delay time for 1/2 cycle
  477.     ADDD    TOC2,X    Add to last compare value
  478.     STD    TOC2,X    Update OC2 (schedule next edge)
  479.     BCLR    TFLG1,X $BF    Clear OC2F
  480.     RTI        ** Return from OC2 service **
  481. *
  482. ***** END Ex 10-5
  483.  
  484. ***
  485. *  TIMER EXAMPLE 10-6
  486. *    OC1, OC2, and OC3 used together to produce 2 PWM signals
  487. *
  488. * OC1 controls two pins of port A in conjunction with OC2 and OC3
  489. * OC1 drives the period and the scheduling of OC2 and OC3
  490. * OC2 & OC3 automatically control pins but don't generate interrupts
  491. * Set "PWMP1P", "PWMDC1" & "PWMDC2" manually before running this example
  492. * "PWMP1P" sets size of a 1% segment of PWM period (cycles)
  493. *    min PWMP1P for this program is 2 (period = 200 cycles)
  494. * "PWMDC1" sets Duty cycle for OC2 pin in % (0 to $64 hex)
  495. * "PWMDC2" sets Duty cycle for OC3 pin in % (0 to $64 hex)
  496. * Duty cycle (%)  will be translated into a # of cycles offset
  497. * and period will be calculated as (100 * PWMP1P) at prog start
  498. * PA4 pin will toggle at each OC1 compare as a scope reference signal
  499. *
  500. * Produces high going PWM signals of the period and duty cycle specified.
  501. * Note actually only produces PWMs of 50% to 100% because spec'd duty of
  502. * 0 to 50% is changed to low going PWM w/ duty cyc = [100% - spec(0-50)]
  503. *
  504. * This program runs on an EVB board and drives output pins.
  505. * An oscilloscope is used to study the results.
  506. ***
  507.  
  508. INZ6    LDS    #$0047    Top of User's stack area on EVB
  509.     LDAA    #$7E    Jump (extended) Opcode
  510.     STAA    PVOC1    OC1 Pseudo Vector see manual text
  511.     LDX    #SV6OC1    Address of OC1 service routine
  512.     STX    PVOC1+1    Finish jump instruc to OC1 routine
  513.     LDX    #REGBAS    Point to register block
  514.     LDAA    #%01010000    OMx:OLx = 0:1 for toggle
  515.     STAA    TCTL1,X    OC2 and OC3 for toggle
  516.     LDAA    #%01110000    OC1M6,5, & 4 = 1
  517.     STAA    OC1M,X    To control OC2/PA6, OC3/PA5, & PA4
  518.     CLRB        Build OC1D initial value in B
  519.     LDAA    PWMDC1    Check for OC2 duty > or = 50%
  520.     CMPA    #50
  521.     BLS    ARNZ61    If <50% OC1 drives low, OC2 toggles high
  522.     ADDB    #%01000000    else OC1 drives high, OC2 toggles low
  523. ARNZ61    LDAA    PWMDC2    Check for OC3 duty > or = 50%
  524.     CMPA    #50
  525.     BLS    ARNZ62    If <50% OC1 drives low, OC3 toggles high
  526.     ADDB    #%00100000    else OC1 drives high, OC3 toggles low
  527. ARNZ62    STAB    OC1D,X    Store starting value for OC1D
  528. * Calculate period & duty cycle as cycle count offsets
  529.     LDAA    PWMP1P    1% of period
  530.     LDAB    #100
  531.     MUL        100 * PWMP1P = PWMPER
  532.     STD    PWMPER    Store period
  533.     STD    TOC1,X    Start first PWM period at TCNT=PWMPER
  534.     LDAA    PWMDC1    Calculate offset for OC2
  535.     BSR    CALOFF    Adj duty as needed and calc offset
  536.     STD    TOC2,X    Schedule first OC2 toggle
  537.     LDAA    PWMDC2    Calculate offset for OC3
  538.     BSR    CALOFF    Adj duty as needed and calc offset
  539.     STD    TOC3,X    Schedule first OC3 toggle
  540. * Finish initialization    
  541.     LDAA    #$80
  542.     STAA    TFLG1,X    OC1F=1 to clear any old OC1 flag
  543.     STAA    TMSK1,X    then OC1I=1 to enable OC1 interrupt
  544.     CLI
  545.  
  546.     BRA    *    From now on OC1 interrupt runs PWMs
  547.  
  548. *** Local subroutine for changing  duty cycle to an offset count
  549. *    If duty < 50% ($32) change to 100-duty
  550. *    If duty >100% ($64) force to $64
  551. *    Finally mult by 1% of period (cyc)
  552. *    Enter with PWMDCx duty in A-reg, Return offset in D-reg
  553. CALOFF    CMPA    #50    Check for 0-49%
  554.     BHS    ARN6A    Around fixup
  555.     TAB        If < 50% - set to 100 - duty cycle
  556.     LDAA    #100
  557.     SBA        A-B to A
  558. ARN6A    CMPA    #100    Check for > 100%
  559.     BLS    ARN6B
  560.     LDAA    #100    If > 100% - set to 100%
  561. ARN6B    LDAB    PWMP1P
  562.     MUL        PWMP1P * adjusted duty cycle = OFFOCx
  563.     RTS        ** Return from CALOFF **
  564. *
  565. **
  566.  
  567. ***
  568. * SV6OC1 - Output Compare 1 service routine
  569. ***
  570. SV6OC1    LDX    #REGBAS    Point to register block
  571.     LDAA    OC1D,X    Make PA4 change state at next OC1 compare
  572.     EORA    #%00010000    Inverts OC1D4 bit (PA4 pin control)
  573.     STAA    OC1D,X    Update next OC1 automatic pattern
  574.     LDD     TOC2,X    Get last OC2 compare value
  575.     ADDD    PWMPER    Add count equiv to period
  576.     STD    TOC2,X    Update OC2 (schedule next OC2)
  577.     LDD     TOC3,X    Get last OC3 compare value
  578.     ADDD    PWMPER    Add count equiv to period
  579.     STD    TOC3,X    Update OC3 (schedule next OC3)    
  580.     LDD     TOC1,X    Get last OC1 compare value
  581.     ADDD    PWMPER    Add count equiv to period
  582.     STD    TOC1,X    Update OC1 (schedule next OC1)
  583.     BCLR    TFLG1,X $7F    Clear OC1F
  584.     RTI        ** Return from OC1 service **
  585. *
  586. ***** END Ex 10-6
  587.  
  588. ***
  589. *  TIMER EXAMPLE 10-7
  590. *    OC2 used alone to produce one PWM signal
  591. *
  592. * OC2 controls period and duty cycle of one port A pin
  593. * Set "PWMP1P" & "PWMDC1" manually before running this example
  594. * "PWMP1P" sets size of a 1% segment of PWM period (cycles)
  595. * "PWMDC1" sets Duty cycle for OC2 pin in % - NOTE: This program will
  596. *   not work properly with values of duty cycle too near 0 or 100%
  597. *   Refer to User's Manual text for discussions
  598. * Program calculates "OFFHI" and "OFFLO" at start
  599. *
  600. * This program runs on an EVB board and drives the PA6/OC2 pin.
  601. * An oscilloscope is used to study the results.
  602. ***
  603.  
  604. INZ7    LDS    #$0047    Top of User's stack area on EVB
  605.     LDAA    #$7E    Jump (extended) Opcode
  606.     STAA    PVOC2    OC2 Pseudo Vector
  607.     LDX    #SV7OC2    Address of OC2 service routine
  608.     STX    PVOC2+1    Finish jump instruc to OC2 routine
  609.     LDX    #REGBAS    Point to register block
  610.  
  611.     LDAA    PWMDC1    Calculate OC2 high time
  612.     LDAB    PWMP1P    1% of period
  613.     MUL        PWMP1P * duty cycle = high part of period
  614.     STD    OFFHI    Save high offset
  615.     LDAA    PWMP1P    1% of period
  616.     LDAB    #100
  617.     MUL        100 * PWMP1P = period
  618.     SUBD    OFFHI    period - high time = low time
  619.     STD    OFFLO    Store low offset
  620.  
  621. * Finish initialization    
  622.     LDAA    #%11000000    OM2:OM1 = 1:1 for set pin high
  623.     STAA    TCTL1,X    First OC2 starts first high time
  624.     LDD    #$0000
  625.     STD    TOC2,X    Start first PWM period at TCNT=$0000
  626.     LDAA    #$40
  627.     STAA    TFLG1,X    OC2F=1 to clear any old OC2 flag
  628.     STAA    TMSK1,X    then OC2I=1 to enable OC2 interrupt
  629.     CLI
  630.     
  631.     BRA    *    From now on OC2 interrupt runs PWM
  632.  
  633. ***
  634. * SV7OC2 - Output Compare 2 service routine
  635. ***
  636. SV7OC2    LDX    #REGBAS    Point to register block
  637.     BRCLR    TCTL1,X %01000000 ADDLO    See which half of cyc
  638.     LDD    OFFHI    High part so we will add OFFHI to OC2
  639.     BRA    UPOC2
  640. ADDLO    LDD    OFFLO    Low part so we will add OFFLO to OC2
  641. UPOC2    ADDD    TOC2,X    Add to last compare value
  642.     STD    TOC2,X    Update OC2 (schedule next edge)
  643.     LDAA    TCTL1,X    Change OL2 to setup for next edge
  644.     EORA    #%01000000    Inverts OL2 bit
  645.     STAA    TCTL1,X    Update control reg
  646.     BCLR    TFLG1,X $BF    Clear OC2F
  647.     RTI        ** Return from OC2 service **
  648. *
  649. ***** END Ex 10-7
  650.  
  651. ***
  652. * General purpose subroutines
  653. ***
  654.  
  655. ***
  656. * P5DEC - Subroutine to display a five digit decimal number at "DBUFR".
  657. *      Prints in the form "xx,xxx" with leading zeros suppressed.
  658. *      Prints 6 columns, leading spaces, units always prints (0-9)
  659. *
  660. * Calls EVB routine ".OUTA"
  661. * Calls "SKP1" with BSR to advance X and print a leading space
  662. *  SKP1 subroutine immediately follows P5DEC
  663. * All registers are unchanged upon return from P5DEC
  664. ***
  665.  
  666. P5DEC    PSHX        Save registers
  667.     PSHB
  668.     PSHA
  669.     LDX    #DBUFR    Point at decimal (MS character)
  670.     LDAA    #$30    Chk for leading 0s (ASCII)
  671.     CMPA    0,X    Check 10,000s digit
  672.     BNE    P10K    Start at 10k digit
  673.     BSR    SKP1    INX & print a space
  674.     CMPA    0,X    Check 1,000s digit (a still=ASCII<sp>)
  675.     BNE    P1K    Start at 1k digit
  676.     BSR    SKP1    INX & print a space
  677.     BSR    SKP1    INX & print a space (extra 1 for ,)
  678.     DEX        just wanted the <sp> so back up 1
  679.     CMPA    0,X    Check 100s digit
  680.     BNE    P100    Start at 100s digit
  681.     BSR    SKP1    INX & print a space
  682.     CMPA    0,X    Check 10s digit
  683.     BNE    P10    Start at 10s digit
  684.     BSR    SKP1    INX & print a space
  685.     BRA    P1    Start at 1s digit (default)
  686.  
  687. P10K    LDAA    0,X    10,000s digit
  688.     JSR    .OUTA    Print 10,000s digit
  689.     INX        Advance pointer to next digt
  690. P1K    LDAA    0,X    1,000s digit
  691.     JSR    .OUTA    Print it
  692.     LDAA    #','    ASCII comma
  693.     JSR    .OUTA    Print
  694.     INX        Advance pointer to next digt
  695. P100    LDAA    0,X    100s digit
  696.     JSR    .OUTA    Print it
  697.     INX        Advance pointer to next digt
  698. P10    LDAA    0,X    10s digit
  699.     JSR    .OUTA    Print it
  700.     INX        Advance pointer to next digt
  701. P1    LDAA    0,X    1s digit
  702.     JSR    .OUTA    Print it
  703.     PULA        Restore registers
  704.     PULB
  705.     PULX
  706.     RTS        ** Return from P5DEC **
  707.  
  708. *** Local SKP1 subroutine (called from above with BSRs)
  709. SKP1    PSHA        Save A
  710.     INX        Advance X
  711.     LDAA    #$20    ASCII <sp>
  712.     JSR    .OUTA    Print the <sp>
  713.     PULA        Restore A
  714.     RTS        ** Return from SKP1 **
  715.  
  716. ***
  717. * HTOD - Subroutine to convert a 16-bit hex number to a
  718. *      5 digit decimal number.
  719. *
  720. * Uses 5 byte variable "DBUFR" for decimal ASCII result
  721. * On entry X points to hex value to be converted & displayed
  722. * All registers are unchanged upon return
  723. ***
  724.  
  725. HTOD    PSHX        Save registers
  726.     PSHB
  727.     PSHA
  728.     LDD    0,X    D=hex value to be converted
  729.     LDX    #10000
  730.     IDIV        freq╓10,000 -> X; r -> D
  731.     XGDX        Save r in X; 10,000s digit in D (A:B)
  732.     ADDB    #$30    Convert to ASCII
  733.     STAB    DBUFR    Store in decimal buffer
  734.     XGDX        r back to D
  735.     LDX    #1000
  736.     IDIV        r╓1,000 -> X; r -> D
  737.     XGDX        Save r in X; 1,000s digit in D (A:B)
  738.     ADDB    #$30    Convert to ASCII
  739.     STAB    DBUFR+1    Store in decimal buffer
  740.     XGDX        r back to D
  741.     LDX    #100
  742.     IDIV        r╓100 -> X; r -> D
  743.     XGDX        Save r in X; 100s digit in D (A:B)
  744.     ADDB    #$30    Convert to ASCII
  745.     STAB    DBUFR+2    Store in decimal buffer
  746.     XGDX        r back to D
  747.     LDX    #10
  748.     IDIV        r╓10 -> X; r in D (B is units digit)
  749.     ADDB    #$30    Convert to ASCII
  750.     STAB    DBUFR+4    Store to units digit
  751.     XGDX        10s digit to D (A:B)
  752.     ADDB    #$30    Convert to ASCII
  753.     STAB    DBUFR+3    Store in decimal buffer
  754.     PULA        Restore registers
  755.     PULB
  756.     PULX
  757.     RTS        ** Return **
  758.  
  759. ***
  760. * H6TOD8 - Subroutine to convert a 24-bit hex number to an
  761. *      8 digit decimal number.
  762. *
  763. * Uses 3 byte variable "HTEMP" for hex working value
  764. * Uses 8 byte variable "DBUFR" for decimal ASCII result
  765. * On entry X points to hex value to be converted & displayed
  766. * All registers are unchanged upon return
  767. ***
  768.  
  769. H6TOD8    PSHY        Save registers
  770.     PSHX
  771.     PSHB
  772.     PSHA
  773.     LDD    1,X    Move hex to HTEMP for conversion
  774.     STD    HTEMP+1    Two lower bytes moved
  775.     LDAA    0,X    Upper byte
  776.     STAA    HTEMP
  777.     LDY    #DBUFR    Point at MS digit of decimal buffer
  778.     LDX    #CON10M    Point at first 24-bit constant
  779.  
  780. HTDLP    CLRA        A keeps track of # of subtractions
  781. HLPIN    INCA        Inner loop; once per subtraction
  782.     LDAB    HTEMP+2    Start 24-bit subtract
  783.     SUBB    2,X
  784.     STAB    HTEMP+2    Update low byte
  785.     LDAB    HTEMP+1    Middle byte
  786.     SBCB    1,X    Sub with carry
  787.     STAB    HTEMP+1    Update middle byte
  788.     LDAB    HTEMP    High byte
  789.     SBCB    0,X
  790.     STAB    HTEMP    Update high byte
  791.     BCC    HLPIN    If no borrow; subtract again
  792.  
  793.     LDAB    HTEMP+2    Last subtract too far; add back
  794.     ADDB    2,X    
  795.     STAB    HTEMP+2    Update low byte
  796.     LDAB    HTEMP+1    Middle byte
  797.     ADCB    1,X    Sub with carry
  798.     STAB    HTEMP+1    Update middle byte
  799.     LDAB    HTEMP    High byte
  800.     ADCB    0,X
  801.     STAB    HTEMP    Update high byte
  802.  
  803.     ADDA    #$2F    Convert digit to ASCII
  804.     STAA    0,Y    Store to decimal buffer
  805.     INY        Point to next decimal digit
  806.     INX        Point to next 24-bit const
  807.     INX
  808.     INX
  809.     CPX    #CONEND See if done yet
  810.     BNE    HTDLP    If not done, do nxt digit
  811.  
  812.     LDAA    HTEMP+2    Get 1s digit
  813.     ADDA    #$30    Convert to ASCII
  814.     STAA    0,Y    Store to last decimal digit
  815.     
  816.     PULA        Restore registers
  817.     PULB
  818.     PULX
  819.     PULY
  820.     RTS        ** Return from H6TOD8 **
  821. *
  822. * Display Messages & Constants
  823. *
  824. MSGCYC    FCC    ' Cycles     '
  825.     FCB    $04    End-of-message mark
  826. MSGHZ    FCC    ' Hz'
  827.     FCB    $04    End-of-message mark
  828. MSGER1    FCC    'Freq. is too high'
  829.     FCB    $04    End-of-message mark
  830. MSGMS    FCC    ' microseconds'
  831.     FCB    $04    End-of-message mark
  832. MSGSEC    FCC    ' Seconds'
  833.     FCB    $04    End-of-message mark
  834.  
  835. CON10M    FCB    $98,$96,$80 = 24-bit equiv of 10,000,000 
  836.     FCB    $0F,$42,$40 = 24-bit equiv of 1,000,000
  837.     FCB    $01,$86,$A0 = 24-bit equiv of 100,000
  838.     FCB    $00,$27,$10 = 24-bit equiv of 10,000
  839.     FCB    $00,$03,$E8 = 24-bit equiv of 1,000
  840.     FCB    $00,$00,$64 = 24-bit equiv of 100
  841.     FCB    $00,$00,$0A = 24-bit equiv of 10
  842. CONEND    EQU    *    Don't need 1s const
  843.  
  844.  
  845. * END OF FILE
  846.